import json
import re
import time
from typing import List, Union

import jmespath

from httpRequest.loader import load_project_meta
from httpRequest.models import TConfig, TStep, StepData, ProjectMeta
from httpRequest.parser import build_url
from httpRequest.response import ResponseObject
from httpRequest.sendRequest import SendRequest
from httpRequest.testcase import Config, StepRequestValidation, StepRequestExtraction, RequestWithOptionalArgs


class HttpRequest(object):
    config: Config

    variables = {}

    __config: TConfig
    __sendRequest: SendRequest = None
    __project_meta: ProjectMeta = None

    def __init_tests__(self):
        self.__config = self.config.perform()
        self.__project_meta = self.__project_meta or load_project_meta(
            self.__config.path
        )

    def TestStep(self, step_context: Union[StepRequestValidation, StepRequestExtraction, RequestWithOptionalArgs]) -> StepData:
        self.__init_tests__()
        self.__sendRequest = self.__sendRequest or SendRequest()
        step = step_context.perform()
        """run teststep: request"""
        print(f"===========  config  =========== \n{self.__config}")
        print(f"===========  step.request  =========== \n{step.request}\n")
        self.__run_step_request(step)

    def __run_step_request(self, step: TStep) -> StepData:
        step_data = StepData(name=step.name)
        request = step.request
        method = request.method.name
        url_path = request.url
        url = build_url(self.__config.base_url, url_path)
        request.url = self.replace_var(request.url)
        request.headers = self.replace_var(request.headers)
        request.data = self.replace_var(request.data)
        request.req_json = self.replace_var(request.req_json)
        print(method, url, request.headers, '\n------request.req_json-----', request.req_json, '\n------request.data-----', request.data)
        resp = self.__sendRequest.request(method, url, **{"headers": request.headers, "data": request.data})
        resp_obj = ResponseObject(resp)
        print(resp.json())

        # extract
        extractors = step.extract
        extract_mapping = resp_obj.extract(extractors, step.variables, self.__project_meta.functions)
        step_data.export_vars = extract_mapping

        variables_mapping = step.variables
        variables_mapping.update(extract_mapping)

        resp_obj.validate(
            step.validators, step.variables, self.__project_meta.functions
        )
        self.variables.update(step.variables)

        print("===================step.variables==================", self.variables)
        return step_data

    def replace_var(self, json_data):
        """
        替换变量：获取格式为 ${var_name} 的字符串，在config.variables查找替换
        @params: json_data json数据
        @return: json_data 返回处理后的json数据
        """
        # 判断传入参数是否为字典
        if json_data:
            json_str = json.dumps(json_data, ensure_ascii=False)
            if "${" in json_str:
                if re.search(r"\S*\$\{(.*?)}\s*", json_str):
                    result = re.findall(r".*?\$\{(.*?)}.*?", json_str)
                    for key in result:
                        json_str = json_str.replace("${%s}" % (key,), str(self.variables[key]))
                return json.loads(json_str)
            else:
                return json_data
        else:
            return json_data
